package com.aliware.tianchi;

public class LoadBalanceManager {
    //ＣＰＵ 剩余利用率
    public static double CSmall = 0.8;
    public static double CMedium = 0.8;
    public static double CLarge = 0.8;
    //内存剩余利用率
    public static double MSmall = 0.8;
    public static double MMedium = 0.8;
    public static double MLarge = 0.8;
    //CPU常量
    private static double K1 = 0.5;
    //内存常量
    private static double K2 = 0.5;
    //服务器初始权值
    private static double WSmall = 0.35;//K1 * 1 + K2 * 1;
    private static double WMedium = 0.55;//K1 * 1.5 + K2 * 2;
    private static double WLarge = 0.85;//K1 * 1.5 + K2 * 3;

    //剩余率阈值
    private static double LCpuThreshold = 0.05;
    private static double LMemThreshold = 0.08;
    private static double LSerThreshold = 0.04;
    //服务器负载剩余
    public static double LLarge = 0.6;
    public static double LSmall = 0.6;
    public static double LMedium = 0.6;
    //台服务器的负载剩余L 计算
    private void calLSmall()
    {
        LSmall = K1 * CSmall + K2 * MSmall;
    }

    private void calLLarge()
    {
        LLarge = K1 * CLarge + K2 * MLarge;
    }

    private void calLMedium()
    {
        LMedium = K1 * CMedium + K2 * MMedium;
    }

    //负载剩余L（i）和权值W（i）的比值为ｒａｔｉｏ＿ＬＷ，
    private double calRatioLWLarge()
    {
        return LLarge / WLarge;
    }

    private double calRatioLWSmall()
    {
        return LSmall / WSmall;
    }

    private double calRatioLWMedium()
    {
        return LMedium / WMedium;
    }


    //权值变化量计算
    private double calDeltaWLarge(double avgRatio)
    {
        return 1 - calRatioLWLarge() / avgRatio;
    }

    private double calDeltaWMedium(double avgRatio)
    {
        return 1 - calRatioLWMedium() / avgRatio;
    }

    private double calDeltaWSmall(double avgRatio)
    {
        return 1 - calRatioLWSmall() / avgRatio;
    }

    private double maxW(double x, double y)
    {
        return x>y?x:y;
    }
    private double maxW(double x, double y,double z)
    {
        double mv = maxW(x,y);
        return mv > z ? mv : z;
    }
    /*
    （２）负载均衡调度器每隔一个周期收集后端每台
    服务器的ＣＰＵ 剩余率和内存剩余率。
    （３）通过收集每台服务器的ＣＰＵ 剩余率和内存剩
    余率，计算负载剩余L（i）。
    （４）判断计算出的负载剩余是否大于已经设置的
    负载剩余率阈值：若大于，执行步骤（５）；若小于则执
    行步骤（６）。
    （５）将该台服务器的ＣＰＵ 剩余率和内存使用剩余
    率分别和先前设置好的阈值相比较，若有其中的任何一
    个参数小于阈值，执行步骤（６）；否则，执行步骤（７）。
    （６）令该服务器的负载剩余为０，执行步骤８。
    （７）计算各个满足条件的服务器的负载剩余，计
    算权值变量ΔW，新的权值W'（i）。
    （８）计算出新的动态权值W'（i），将其根据划分组
    别的要求分配到相应的组别。
    （９）选出权值最高的一组服务器，通过静态算法
    中的轮转算法，将更多的任务请求分配到权值较高的
    服务器组。
     */
    public String getInvoker()
    {
        String result;
        boolean LL = true,LM = true,LS = true;
        //计算负载剩余
//        calLSmall();
//        calLLarge();
//        calLMedium();
        //负载剩余,CPU剩余率和内存剩余率任一个低于阈值，都将负载剩余置为0
        if (LLarge < LSerThreshold ||
                CLarge < LCpuThreshold || MLarge < LMemThreshold)
        {
            LLarge = 0;
            LL = false;
        }
        if (LMedium < LSerThreshold ||
                CMedium < LCpuThreshold || MMedium < LMemThreshold)
        {
            LMedium = 0;
            LM = false;
        }
        if (LSmall < LSerThreshold ||
                CSmall < LCpuThreshold || MSmall < LMemThreshold)
        {
            LSmall = 0;
            LS = false;
        }

        result = cal(LL,LM,LS);
        return result;
    }

    private String cal(boolean LL,boolean LM, boolean LS)
    {
        double avgRatio = 0;
        int avgCount = 0;
        String result = "large";
        if (LL)
        {
            avgRatio += calRatioLWLarge();
            avgCount ++;
        }
        if (LM)
        {
            avgRatio += calRatioLWMedium();
            avgCount ++;
        }
        if (LS)
        {
            avgRatio += calRatioLWSmall();
            avgCount ++;
        }
        if (avgCount > 0) avgRatio = avgRatio / avgCount;

        if (LL) WLarge = WLarge + calDeltaWLarge(avgRatio);
        if (LM) WMedium = WMedium + calDeltaWMedium(avgRatio);
        if (LS) WSmall = WSmall + calDeltaWSmall(avgRatio);

        double maxWV = maxW(WSmall, WMedium, WLarge);
        if (maxWV == WLarge)
        {
            result = "large";
        }else if (maxWV == WMedium)
        {
            result = "medium";
        }else if (maxWV == WSmall)
        {
            result = "small";
        }

        System.out.println(WSmall + " " + WMedium + " " + WLarge);
        return result;
    }

    private static long iCount = 0;
    public String sample()
    {
        String result = "";
        long c = iCount % 6;
        if (c == 0) result = "small";
        else if (c == 1 || c == 3) result = "medium";
        else result = "large";
        iCount ++;
        return result;
    }
}
